#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>
#include "LockGuard.hpp"

const int g_default_capacity = 5;

template <class T>
class BlockQueue
{
private:
    bool fullBlockQueue()
    {
        return _bq_.size() == _capacity_;
    }

    bool emptyBlockQueue()
    {
        return _bq_.size() == 0;
    }

private:
    pthread_mutex_t _mutex_; // 互斥锁
    pthread_cond_t _empty_;  // 条件变量
    pthread_cond_t _full_;   // 条件变量
    int _capacity_;          // 阻塞队列的容量
    std::queue<T> _bq_;      // 阻塞队列

public:
    BlockQueue(int capacity = g_default_capacity) : _capacity_(capacity)
    {
        // 初始化锁和条件变量
        pthread_mutex_init(&_mutex_, nullptr);
        pthread_cond_init(&_empty_, nullptr);
        pthread_cond_init(&_full_, nullptr);
    }

    void push(const T &in)
    {
        {
            LockGuard lockG(_mutex_);
            // 如果临界资源不满足条件则进行等待,也即阻塞队列为满
            while (fullBlockQueue())
            {
                pthread_cond_wait(&this->_full_, &this->_mutex_);
            }

            // 当被唤醒时,才进行生产
            _bq_.push(in);

            // 生产之后就可以进行消费
            pthread_cond_signal(&this->_empty_);
        }
    }

    void pop(T *out)
    {
        {
            LockGuard lockG(_mutex_);
            // 如果阻塞队列为空则进行等待
            while (emptyBlockQueue())
            {
                pthread_cond_wait(&this->_empty_, &this->_mutex_);
            }

            // 当被唤醒时,才进行消费
            *out = _bq_.front();
            _bq_.pop();

            // 消费之后就可以进行生产
            pthread_cond_signal(&this->_full_);
        }
    }

    // void push(const T &in)
    // {
    //     // 通过判断临界资源是否满足条件来进行生产
    //     // 判断临界资源也需要访问临界资源所以需要进行加锁与解锁
    //     pthread_mutex_lock(&this->_mutex_);

    //     // 如果临界资源不满足条件则进行等待,也即阻塞队列为满
    //     while(fullBlockQueue())
    //     {
    //         pthread_cond_wait(&this->_full_,&this->_mutex_);
    //     }

    //     // 当被唤醒时,才进行生产
    //     _bq_.push(in);

    //     // 生产之后就可以进行消费
    //     pthread_cond_signal(&this->_empty_);

    //     pthread_mutex_unlock(&this->_mutex_);

    // }

    // void pop(T *out)
    // {
    //     pthread_mutex_lock(&this->_mutex_);

    //     // 如果阻塞队列为空则进行等待
    //     while(emptyBlockQueue())
    //     {
    //         pthread_cond_wait(&this->_empty_,&this->_mutex_);
    //     }

    //     // 当被唤醒时,才进行消费
    //     *out=_bq_.front();
    //     _bq_.pop();

    //     // 消费之后就可以进行生产
    //     pthread_cond_signal(&this->_full_);

    //     pthread_mutex_unlock(&this->_mutex_);
    // }

    ~BlockQueue()
    {
        // 销毁锁和条件变量
        pthread_mutex_destroy(&_mutex_);
        pthread_cond_destroy(&_empty_);
        pthread_cond_destroy(&_full_);
    }
};